// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <map>
#include "../CasCommon.h"
#include "CasLog.h"
#include "CasMsg.h"
#include "CasGadget.h"
#include "CasCmdControlThread.h"
#include "CasAppCtrlCmdUtils.h"

using namespace std;

CasCmdControlThread::CasCmdControlThread(CasCmdController *controller)
{
    this->m_controlStream = nullptr;
    this->m_controlTask = nullptr;
    this->m_cmdController = controller;
}

CasCmdControlThread::~CasCmdControlThread()
{
    if (this->m_controlTask != nullptr) {
        delete this->m_controlTask;
        this->m_controlTask = nullptr;
    }

    this->m_controlStream = nullptr;
    this->m_cmdController = nullptr;
}

void CasCmdControlThread::SetControlPktHandle(CasDataPipe *controlStream)
{
    this->m_controlStream = controlStream;
}

CasDataPipe *CasCmdControlThread::GetControlStream()
{
    return this->m_controlStream;
}

CasCmdController *CasCmdControlThread::GetController()
{
    return this->m_cmdController;
}

int CasCmdControlThread::GetThreadStatus()
{
    return this->m_threadStatus;
}

void TaskEntry(CasCmdControlThread *threadObj)
{
    CasDataPipe *controlPktStream = threadObj->GetControlStream();
    CasCmdController *controller = threadObj->GetController();
    void *onePkt = nullptr;

    while (threadObj->GetThreadStatus() == CAS_THREAD_RUNNING || threadObj->GetThreadStatus() == CAS_THREAD_STOP) {
        if (threadObj->GetThreadStatus() == CAS_THREAD_STOP) {
            usleep(100 * 1000);
            continue;
        }

        int pktNum = controlPktStream->GetNumItems();
        if (pktNum == 0) {
            usleep(100);
            continue;
        } else {
            DBG("Number of packet is %d.", pktNum);
        }

        onePkt = controlPktStream->GetNextPkt();
        if (onePkt == nullptr) {
            ERR("Next packet is nullptr.");
            continue;
        }

        controller->HandleReceivedCtrlCmdFromServer(onePkt);
    }
    return;
}

int CasCmdControlThread::Start()
{
    if (this->m_threadStatus == CAS_THREAD_RUNNING) {
        return -1;
    }

    this->m_threadStatus = CAS_THREAD_INIT;
    this->m_controlTask = new(std::nothrow) thread(TaskEntry, this);

    if (this->m_controlTask == nullptr) {
        ERR("Task thread is nullptr.");
        return -1;
    }

    if (this->m_controlTask->joinable()) {
        this->m_controlTask->detach();
    }

    this->m_threadStatus = CAS_THREAD_RUNNING;
    return 0;
}

int CasCmdControlThread::Restart()
{
    if (this->m_threadStatus == CAS_THREAD_STOP) {
        this->m_threadStatus = CAS_THREAD_RUNNING;
        return 0;
    }
    return -1;
}

int CasCmdControlThread::Stop()
{
    if (this->m_threadStatus == CAS_THREAD_RUNNING) {
        this->m_threadStatus = CAS_THREAD_STOP;
        return 0;
    }
    return -1;
}

int CasCmdControlThread::Exit()
{
    if (this->m_threadStatus == CAS_THREAD_RUNNING || this->m_threadStatus == CAS_THREAD_STOP) {
        if (this->m_threadStatus != CAS_THREAD_EXIT) {
            this->m_threadStatus = CAS_THREAD_EXIT;
            return 0;
        }
    }
    return -1;
}